﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml;
using System.Collections;
using System.Web;
using System.IO;

namespace WCollection.Utils {

    public class WebServiceInvoker {
        private static Hashtable _xmlNamespaces = new Hashtable();

        public static XmlDocument GetWSDL(String url, String medthodName, Hashtable Pars) {

            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url + "/" + medthodName);
            request.ContentType = "application/x-www-form-urlencoded";
            byte[] data = EncodePars(Pars);

            return ReadXmlResponse(request.GetResponse());
        }

        public static XmlDocument QueryGetWebService(String URL, String MethodName, Hashtable Pars) {

            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL + "/" + MethodName + "?" + ParsToString(Pars));

            request.Method = "GET";

            request.ContentType = "application/x-www-form-urlencoded";

            SetWebRequest(request);

            return ReadXmlResponse(request.GetResponse());

        }

        public static XmlDocument QuerySoapWebService(String URL, String MethodName, Hashtable Pars) {


            if (_xmlNamespaces.ContainsKey(URL)) {

                return QuerySoapWebService(URL, MethodName, Pars, _xmlNamespaces[URL].ToString());

            }

            else {

                return QuerySoapWebService(URL, MethodName, Pars, GetNamespace(URL));

            }

        }

        private static XmlDocument QuerySoapWebService(String URL, String MethodName, Hashtable Pars, string XmlNs) {

            _xmlNamespaces[URL] = XmlNs;//加入缓存，提高效率

            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL);

            request.Method = "POST";

            request.ContentType = "text/xml; charset=utf-8";

            request.Headers.Add("SOAPAction", "\"" + XmlNs + (XmlNs.EndsWith("/") ? "" : "/") + MethodName + "\"");

            SetWebRequest(request);

            byte[] data = EncodeParsToSoap(Pars, XmlNs, MethodName);

            WriteRequestData(request, data);

            XmlDocument doc = new XmlDocument(), doc2 = new XmlDocument();

            doc = ReadXmlResponse(request.GetResponse());



            XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);

            mgr.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");

            String RetXml = doc.SelectSingleNode("//soap:Body/*", mgr).InnerXml;

            doc2.LoadXml("<root>" + RetXml + "</root>");

            AddDelaration(doc2);

            return doc2;

        }

        private static string GetNamespace(String URL) {

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL + "?WSDL");

            SetWebRequest(request);

            WebResponse response = request.GetResponse();

            StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8);

            XmlDocument doc = new XmlDocument();

            doc.LoadXml(sr.ReadToEnd());

            return doc.SelectSingleNode("//@targetNamespace").Value;

        }

        private static byte[] EncodeParsToSoap(Hashtable Pars, String XmlNs, String MethodName) {

            XmlDocument doc = new XmlDocument();

            doc.LoadXml("<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"></soap:Envelope>");

            AddDelaration(doc);

            XmlElement soapBody = doc.CreateElement("soap", "Body", "http://schemas.xmlsoap.org/soap/envelope/");

            XmlElement soapMethod = doc.CreateElement(MethodName);

            soapMethod.SetAttribute("xmlns", XmlNs);

            foreach (string k in Pars.Keys) {

                XmlElement soapPar = doc.CreateElement(k);

                soapPar.InnerText = Pars[k].ToString();

                soapMethod.AppendChild(soapPar);

            }

            soapBody.AppendChild(soapMethod);

            doc.DocumentElement.AppendChild(soapBody);

            return Encoding.UTF8.GetBytes(doc.OuterXml);

        }

        private static void SetWebRequest(HttpWebRequest request) {

            request.Credentials = CredentialCache.DefaultCredentials;

            request.Timeout = 10000;

        }

        private static void WriteRequestData(HttpWebRequest request, byte[] data) {

            request.ContentLength = data.Length;

            Stream writer = request.GetRequestStream();

            writer.Write(data, 0, data.Length);

            writer.Close();

        }

        private static byte[] EncodePars(Hashtable Pars) {

            return Encoding.UTF8.GetBytes(ParsToString(Pars));

        }

        private static String ParsToString(Hashtable Pars) {

            StringBuilder sb = new StringBuilder();

            foreach (string k in Pars.Keys) {

                if (sb.Length > 0) {

                    sb.Append("&");

                }

                sb.Append(HttpUtility.UrlEncode(k) + "=" + HttpUtility.UrlEncode(Pars[k].ToString()));

            }

            return sb.ToString();

        }

        private static XmlDocument ReadXmlResponse(WebResponse response) {

            using (StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.UTF8)) {

                String retXml = sr.ReadToEnd();


                XmlDocument doc = new XmlDocument();

                doc.LoadXml(retXml);

                return doc;
            }

        }

        private static void AddDelaration(XmlDocument doc) {

            XmlDeclaration decl = doc.CreateXmlDeclaration("1.0", "utf-8", null);

            doc.InsertBefore(decl, doc.DocumentElement);

        }

    }
}
